package com.qfedu.knowledge.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qfedu.knowledge.entity.constant.ElasticSearchConsant;
import com.qfedu.knowledge.entity.dto.AddQuestion4ESDTO;
import com.qfedu.knowledge.entity.dto.BasePageDTO;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;

/**
 * @ClassName ElasticSearchUtils
 * 搜索引擎工具类
 * @Author ykx
 * @Date 2024/4/17 12:12
 * @Version 1.0
 */
@Component
public class ElasticSearchUtils {

    @Autowired
    private RestHighLevelClient highLevelClient;


    @Autowired
    private ObjectMapper objectMapper;

    public SearchSourceBuilder BuildSearchSourcePage(BasePageDTO basePageDTO) {
        SearchSourceBuilder builder = new SearchSourceBuilder();
        // 没有from，size默认是第1页查10条数据
        if (Objects.nonNull(basePageDTO)) {
            builder.from((basePageDTO.getPage() - 1) * basePageDTO.getSize());
            builder.size(basePageDTO.getSize());
        }
        return builder;
    }

    public SearchRequest getRequest() {
        SearchRequest searchRequest = new SearchRequest(ElasticSearchConsant.INDEX);
        searchRequest.types(ElasticSearchConsant.TYPE);
        return searchRequest;
    }


    @SneakyThrows
    public void add(Object o) {
        //创建request对象
        BulkRequest request = new BulkRequest();

        request.add(new IndexRequest(ElasticSearchConsant.INDEX, ElasticSearchConsant.TYPE, o.hashCode() + "")
                .source(objectMapper.writeValueAsString(o), XContentType.JSON));
        highLevelClient.bulk(request, RequestOptions.DEFAULT);
    }

    @SneakyThrows
    public void add(Object o, Long id) {
        //创建request对象
        BulkRequest request = new BulkRequest();

        request.add(new IndexRequest(ElasticSearchConsant.INDEX, ElasticSearchConsant.TYPE, id + "")
                .source(objectMapper.writeValueAsString(o), XContentType.JSON));
        highLevelClient.bulk(request, RequestOptions.DEFAULT);
    }

    @SneakyThrows
    public void addBatch(List<AddQuestion4ESDTO> list) {
        //1. 创建Request，将准备好的数据封装进去
        BulkRequest request = new BulkRequest();
        for (AddQuestion4ESDTO o : list) {
            request.add(new IndexRequest(ElasticSearchConsant.INDEX, ElasticSearchConsant.TYPE, o.getId() + "")
                    .source(objectMapper.writeValueAsString(o), XContentType.JSON));
        }
        highLevelClient.bulk(request, RequestOptions.DEFAULT);
    }

    @SneakyThrows
    public SearchResponse termQuery(String name, Object value, BasePageDTO basePageDTO) {
        SearchSourceBuilder builder = BuildSearchSourcePage(basePageDTO);
        builder.query(QueryBuilders.termQuery(name, value));
        SearchRequest searchRequest = getRequest().source(builder);
        return highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    }

    @SneakyThrows
    public SearchResponse termsQuery(String name, Object[] values, BasePageDTO basePageDTO) {
        SearchSourceBuilder builder = BuildSearchSourcePage(basePageDTO);
        builder.query(QueryBuilders.termsQuery(name, values));
        SearchRequest searchRequest = getRequest().source(builder);
        return highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    }

    @SneakyThrows
    public SearchResponse matchAllQuery(BasePageDTO basePageDTO) {
        SearchSourceBuilder builder = BuildSearchSourcePage(basePageDTO);
        builder.query(QueryBuilders.matchAllQuery());
        SearchRequest searchRequest = getRequest().source(builder);
        //3. 执行查询
        return highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    }

    @SneakyThrows
    public SearchResponse matchQuery(String name, String text, BasePageDTO basePageDTO) {
        SearchSourceBuilder builder = BuildSearchSourcePage(basePageDTO);
        builder.query(QueryBuilders.matchQuery(name, text));
        SearchRequest searchRequest = getRequest().source(builder);
        return highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    }

    @SneakyThrows
    public SearchResponse multiMatchQuery(Object text, BasePageDTO basePageDTO, String... fieldNames) {
        SearchSourceBuilder builder = BuildSearchSourcePage(basePageDTO);
        builder.query(QueryBuilders.multiMatchQuery(text, fieldNames));
        SearchRequest searchRequest = getRequest().source(builder);
        //3. 执行查询
        return highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    }

    @SneakyThrows
    public SearchResponse booleanMatchQuery(String name, String text, BasePageDTO basePageDTO, Operator operator) {
        SearchSourceBuilder builder = BuildSearchSourcePage(basePageDTO);
        builder.query(QueryBuilders.matchQuery(name, text).operator(operator));
        SearchRequest searchRequest = getRequest().source(builder);
        return highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    }

    /**
     * 单字段高亮
     *
     * @param name        字段名
     * @param text        查询结果
     * @param basePageDTO 分页
     * @return es响应数据
     */
    @SneakyThrows
    public SearchResponse highLightQuery(String name, String text, BasePageDTO basePageDTO) {
        SearchSourceBuilder builder = BuildSearchSourcePage(basePageDTO);
        // 指定查询条件
        if (StringUtils.isNotEmpty(text)) {
            builder.query(QueryBuilders.matchQuery(name, text));
        }

        // 设置高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field(name, 100)
                .preTags(ElasticSearchConsant.PRE_TAGS)
                .postTags(ElasticSearchConsant.POST_TAGS)
        ;

        builder.highlighter(highlightBuilder);
        SearchRequest searchRequest = getRequest().source(builder);

        return highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    }

    /**
     * 多字段高亮
     *
     * @param columns     字段名
     * @param text        查询结果
     * @param basePageDTO 分页
     * @return es响应数据
     */
    @SneakyThrows
    public SearchResponse highLightQuery(String[] columns, String text, BasePageDTO basePageDTO) {
        SearchSourceBuilder builder = BuildSearchSourcePage(basePageDTO);
        // 指定查询条件
        if (StringUtils.isNotEmpty(text)) {
            builder.query(QueryBuilders.multiMatchQuery(text, columns));
        }

        // 设置高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        for (String column : columns) {
            highlightBuilder.field(column, 100)
                    .preTags(ElasticSearchConsant.PRE_TAGS)
                    .postTags(ElasticSearchConsant.POST_TAGS)
            ;
        }

        builder.highlighter(highlightBuilder);
        SearchRequest searchRequest = getRequest().source(builder);

        return highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    }

}
